modprobe
modprobe
这个命令是用来往内核中加载(或者移除)模块用的,我很奇怪加载不应该是 insmod
的么?然后查了一下,他们是有区别的,虽然都可以用来往内网中加载模块:
insmod
:指定哪个模块就是哪个模块,不会加载依赖的模块modprobe
:指定哪个模块,不仅可以加载该模块,还会自动加载依赖的其他模块
如果 modprobe
在加载过程中发生错误,会卸载整组的模块。modprobe
寻找模块的位置是:/lib/modules/<uname -r>
,但是不会加载 /etc/modprobe.conf
和 /etc/modprobe.d/
中配置的排除内容。
当然,modprobe
的依赖分析不是天马行空来的,而是通过 depmod
生成的。
- 内核模块相关命令
lsmod
:显示已经加载到内核中的模块的状态信息;rmmod
:从内核中移除指定模块(modprobe 也是和 insmod 对应的效果);dmesg
:查看加载或者卸载过程中的错误日志;modinfo
:显示给定模块的详细信息;
动态库的查找过程
任何一个动态链接的模块所依赖的模块路径保存在 .dynamic
段里面,由 DT_NEED 类型的项表示。动态链接器对于模块的查找有一定的规则:
- 如果 DT_NEED 里面保存的是绝对路径,那么动态链接器就按照这个路径去查找;
- 如果 DT_NEED 里面保存的是相对路径,那么动态链接器会在
/lib
、/usr/lib
和由/etc/ld.so.conf
配置文件指定的目录中查找共享库。
ld.so.conf
是一个文本配置文件,它可能包含其他的配置文件,这些配置文件中存放着目录信息。如果动态链接器在每次查找共享库时都去遍历这些目录,那将会非常耗时。所以 Linux 系统中都有一个叫做 ldconfig
的程序,这个程序的作用是为共享库目录下的各个共享库创建、删除或更新相应的 SO_NAME,这样每个共享库的 SO-NAME 就能够指向正确地共享库文件;并且这个程序还会将这些 SO-NAME 收集起来,集中存放到 /etc/ld.so.cache
文件里面,并建立一个 SO-NAME 的缓存。当动态链接库要查找共享库时,它可以直接从 /etc/ld.so.cache
里面查找,而 /etc/ld.so.cache
的结构是经过特殊设计的,非常适合查找,所以这个设计大大加快了共享库的查找过程。
如果动态链接器在 /etc/ld.so.cache
里面没有找到所需要的共享库,那么它还会遍历 /lib
和 /usr/lib
这两个目录,如果还是没找到,就宣告失败。
所以理论上讲,如果我们在系统指定的共享库目录下添加、删除或者更新任何一个共享库,或者我们更新了 /etc/ld.so.conf
的配置,都应该运行 ldconfig
这个程序,以便调整 SO-NAME 和 /etc/ld.so.cache
。很多软件包的安装程序在往系统里面安装共享库以后都会调用 ldconfig
。
ldconfig
ldconfig
这个命令的作用就是在指定的位置查找动态链接库,然后加载进系统的内存(内核空间还是用户空间?没有深究)。所以,一般这个命令是在系统启动的时候运行的,这样,在我们升级或者自己编译新的动态链接库之后,就需要自己手动执行一遍 ldconfig
才能让新的动态链接库生效。
ldconfig
会将加载的动态链接库的记录都存放在一个文件中,该文件位于:/etc/ld.so.cache
;ldconfig
做的事情都是和运行程序时相关,跟编译时一点关系都没有,编译的时候该加-L
还是得加,不要混淆;- 动态链接库文件里面是会包含库的元数据信息的,因此仅通过修改文件名以冒充某已被识别的库是行不通的;
环境变量
LD_LIBRARY_PATH
在 Linux 系统中,LD_LIBRARY_PATH
是一个由若干个路径组成的环境变量,每个路径之间由冒号隔开。默认情况下,LD_LIBRARY_PATH
为空。如果我们为某个进程设置了 LD_LIBRARY_PATH
,那么进程在启动时,动态链接器在查找共享库时,会首先查找由 LD_LIBRARY_PATH
指定的目录。这个环境可以很方便地让我们测试新的共享库或使用非标准的共享库。
示例:LD_LIBRARY_PATH=/home/liqiang.io /bin/ls
当然,还有另外一个等价的使用方式:
[root@liqiang.io]# /lib/ld-linux.so.2 -library-path /home/liqiang.io /bin/ls
所以,当引入 LD_LIBRARY_PATH
之后,我们总结动态链接器查找共享库的顺序为:
- 由环境变量
LD_LIBRARY_PATH
指定的路径; - 由路径缓存文件
/etc/ld.so.cache
指定的路径; - 默认共享库目录,先
/usr/lib
,再/lib
LD_PRELOAD
系统还存在另外一个环境变量叫做 LD_PRELOAD
,这个文件中我们可以指定预先装载的一些共享库或者目标文件。在 LD_PRELOAD
里面指定的文件会在动态链接器按照固定规则搜索共享库之前装载,它比 LD_LIBRARY_PATH
里面所指定的目录中的共享库还要优先。无论程序是否依赖于它们,LD_LIBRARY_PATH
里面指定的共享库或目标文件都会被装载。
由于全局符号介入这个机制的存在,LD_PRELOAD
里面指定的共享库或目标文件中的全局符号就会覆盖后面加载的同名全局符号,这使得我们可以很方便地做到改写标准 C 库中的某个或某几个函数而不影响其他函数,对于程序的调试或测试非常有用。
(/etc/ld.so.preload
)等效于这个环境变量。
LD_DEBUG
还有一个非常有用的环境变量是 LD_DEBUG
,这个变量可以打开动态链接器的调试功能,当我们设置这个变量时,动态链接器会在运行时打印出各种有用的信息,对于我们开发和调试共享库有很大的帮助。
LD_DEBUG
的可选值有:
- files: 打印出整个状态过程,显示程序依赖于哪个共享库并且按照什么步骤装载和初始化,共享库转载时的地址等;
- bingdings:显示动态链接的符号绑定过程;
- libs:显示共享库的查找过程;
- versions:显示符号的版本依赖关系;
- reloc:显示重定位过程;
- symbols:显示符号表查找过程;
- statistics:显示动态链接过程中的各种统计信息;
- all:显示以上所有信息;
- help:显示上面的各种可选值的帮助信息